package com.senseauto.mediamuxerdemo;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import android.widget.Button;

import com.senseauto.mediamuxerdemo.muxer.MediaMuxerThreadNew;

import java.io.File;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

public class MediaCodecActivity extends AppCompatActivity {
    private static final String TAG = "MediaCodecActivity";
    private TextureView previewTextureView;
    private Button recordButton;
    private Size previewSize = new Size(1920, 1080);
    private String mCameraId = "1";
    private Handler cameraHandler;
    private Handler mainHandler;
    public static String SIMPLE_DATA_FORMAT_FILE_NAME = "yyyy_MM_dd_HH_mm_ss_SSS";

    private CameraDevice mCameraDevice;
    private ImageReader previewImageReader;
    private CaptureRequest.Builder previewCaptureRequestBuilder;
    private CameraCaptureSession previewCaptureSession;
    private boolean isRecording = false;//控制界面显示状态的
    MediaMuxerThreadNew mediaMuxer;
    Object mImageDataLock = new Object();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_media_codec);
        previewTextureView = findViewById(R.id.texture);
        recordButton = findViewById(R.id.startRecord);
        recordButton.setOnClickListener(v->{
            if(!isRecording){
                isRecording = true;
                //每次重新录制都需要重新创建一个对象
                mediaMuxer = new MediaMuxerThreadNew();
                mediaMuxer.init(1920, 1080);
                recordButton.setText("录制中...");
                SimpleDateFormat sdf = new SimpleDateFormat(SIMPLE_DATA_FORMAT_FILE_NAME);
                String fileName = sdf.format(new Date())+".mp4";
                File file = new File(getExternalCacheDir(), fileName);
                Log.e(TAG, "filePath="+file.getAbsolutePath());
                mediaMuxer.setVideoName(file.getAbsolutePath());
                mediaMuxer.startMuxer();
            }else{
                isRecording = false;
                recordButton.setText("录制");
                mediaMuxer.stopMuxer();
            }
        });
        findViewById(R.id.back).setOnClickListener(v->{
            finish();
        });

        mainHandler = new Handler(Looper.getMainLooper());
        previewTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surfaceTexture, int width, int height) {
                Log.e(TAG, "onSurfaceTextureAvailable");
                setupCamera();
                //解决预览时，平板横屏会逆时针旋转90的画面的情况
                configureTransform(width, height);
            }

            @Override
            public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surfaceTexture, int width, int height) {
                Log.e(TAG, "onSurfaceTextureSizeChanged->configureTransform");

            }

            @Override
            public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surfaceTexture) {
                return false;
            }

            @Override
            public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surfaceTexture) {

            }
        });
        HandlerThread videoRecordThread = new HandlerThread("VideoRecordThread");
        videoRecordThread.start();
        cameraHandler = new Handler(videoRecordThread.getLooper());
    }

    private void configureTransform(int viewWidth, int viewHeight) {
        Activity activity = this;
        if (null == previewTextureView || null == activity) {
            return;
        }

        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        Log.e(TAG, "configureTransform rotation="+rotation);
        Matrix matrix = new Matrix();
        RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
        RectF bufferRect = new RectF(0, 0, viewHeight, viewWidth);
        float centerX = viewRect.centerX();
        float centerY = viewRect.centerY();

        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
            float scale = Math.max(
                    (float) viewHeight / viewHeight,
                    (float) viewWidth / viewWidth);
            matrix.postScale(scale, scale, centerX, centerY);
            matrix.postRotate(90 * (rotation - 2), centerX, centerY);
        }
        previewTextureView.setTransform(matrix);
    }

    private void setupCamera() {
        Log.e(TAG, "setupCamera()");

        CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        try {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                Log.e(TAG, "没有摄像头权限");
                return;
            }
            cameraManager.openCamera(mCameraId, stateCallback, cameraHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
            Log.e(TAG, "openCamera 报错");
        }
    }

    private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {

        @Override
        public void onOpened(@NonNull CameraDevice cameraDevice) {
            Log.e(TAG, "onOpen");
            mCameraDevice = cameraDevice;
            startPreview(mCameraDevice);
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice cameraDevice) {
            Log.e(TAG, "onDisconnected");
        }

        @Override
        public void onError(@NonNull CameraDevice cameraDevice, int i) {
            Log.e(TAG, "onError");
        }
    };
    private void setPreviewImageReader() {
        previewImageReader = ImageReader.newInstance(previewSize.getWidth(), previewSize.getHeight(), ImageFormat.YUV_420_888, 1);
        previewImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader imageReader) {
                //Log.e(TAG,"onImageAvailable");
                Image image = imageReader.acquireNextImage();
                int width = image.getWidth();
                int height = image.getHeight();


                if(isRecording){
                    if(width==previewSize.getWidth() && height == previewSize.getHeight()){
                        int mImageDataSize = width * height*3/2;
                        byte[]mImageData = new byte[mImageDataSize];
                        ByteBuffer bufferY = image.getPlanes()[0].getBuffer();
                        byte[] dataY = new byte[bufferY.remaining()];
                        bufferY.get(dataY);


                        ByteBuffer bufferVU = image.getPlanes()[1].getBuffer();
                        byte[] dataVU = new byte[bufferVU.remaining()];
                        bufferVU.get(dataVU);
                        image.close();
                        //planes[0]+planes[2] 就是nv21的组合数据??这个结论是对的吗
                        //VideoEncoderThreadNew我们设置的颜色格式是COLOR_FormatYUV420Flexible（换成COLOR_FormatYUV420SemiPlanar也是planes[0]+planes[1] 不变色，在小米平板上），它通常期望的是YUV420P（即I420）或YUV420SemiPlanar（NV12）格式，而不是NV21。NV12的格式由planes[0]+planes[1] 得到，不会有变色
                        synchronized (mImageDataLock) {
                            System.arraycopy(dataY, 0, mImageData, 0, dataY.length);
                            System.arraycopy(dataVU, 0, mImageData, width * height, dataVU.length);
                        }
                        mediaMuxer.addVideoFrameData(mImageData);
                    }else{
                        Log.e(TAG, "宽度不匹配 width="+width+" height="+height+" previewSize.getWidth()="+previewSize.getWidth()+" previewSize.getHeight()="+previewSize.getHeight());
                    }
                }

                image.close();
            }
        }, cameraHandler);
    }
    private void startPreview(CameraDevice mCameraDevice) {
        try {
            Log.e(TAG, "startPreview");
            setPreviewImageReader();
            previewCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            SurfaceTexture previewSurfaceTexture = previewTextureView.getSurfaceTexture();
            previewSurfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
            Surface previewSurface = new Surface(previewSurfaceTexture);
            Surface previewImageReaderSurface = previewImageReader.getSurface();
            previewCaptureRequestBuilder.addTarget(previewSurface);
            previewCaptureRequestBuilder.addTarget(previewImageReaderSurface);

            mCameraDevice.createCaptureSession(Arrays.asList(previewSurface, previewImageReaderSurface), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                    Log.e(TAG, "onConfigured");
                    previewCaptureSession = cameraCaptureSession;
                    try {
                        cameraCaptureSession.setRepeatingRequest(previewCaptureRequestBuilder.build(), cameraPreviewCallback, cameraHandler);
                    } catch (CameraAccessException e) {
                        throw new RuntimeException(e);
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {

                }
            }, cameraHandler);

        } catch (CameraAccessException e) {
            throw new RuntimeException(e);
        }
    }


    private CameraCaptureSession.CaptureCallback cameraPreviewCallback=new CameraCaptureSession.CaptureCallback() {
        @Override
        public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
            super.onCaptureCompleted(session, request, result);
            //Log.e(TAG, "onCaptureCompleted");
        }
    };

}